package com.telit.firecommand.facade;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.MD5;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.util.ClassUtil;
import com.telit.common.config.SmsAliServerConfig;
import com.telit.common.dto.SmsRealFireDto;
import com.telit.common.dto.SmsSuspectedFireDto;
import com.telit.common.entity.DataReturn;
import com.telit.common.exception.ForestBaseException;
import com.telit.common.util.RedisUtils;
import com.telit.common.util.SmsUtils;
import com.telit.firecommand.controller.HistoryFireController;
import com.telit.firecommand.dao.CommFireSmsLogsDao;
import com.telit.firecommand.dto.MultimediaDTO;
import com.telit.firecommand.entity.CommFireAlarm;
import com.telit.firecommand.entity.CommFireOnemap;
import com.telit.firecommand.entity.CommFireSmsLogs;
import com.telit.firecommand.entity.CommHistoryFire;
import com.telit.firecommand.service.FireQueryService;
import com.telit.firecommand.service.UserInfoService;
import com.telit.firecommand.vo.PubSmsPushUriFireInfoVo;
import com.telit.firecommand.vo.PubSmsPushUriForestryInfoVo;
import com.telit.firecommand.vo.PubSmsPushUriVo;
import com.telit.firecommand.vo.PubSmsPushUriWeatherInfoVo;
import com.telit.upms.vo.MicroSysUserAllInfoVo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

/**
 * @author yuzhanxiang
 * @description: 短信推送不鉴权service
 * @copyright 天立泰科技股份有限公司
 * @since 2022/4/22 17:47
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class SmsPushUriPubFacadeService {

    /**
     * 短信推送火情查询数据保存时间（5天）
     */
    private final static long KEY_EXPIRE_TIME = 60L;
    private final static long KEY_EXPIRE_TIME_FID = 5L * 24L * 60L * 60L;
    private final static String PREFIX_KEY = "sms:h5:{}";
    private final static String PREFIX_KEY_FID = "sms:h5:{}:fid";


//    private final CommFireOnemapServiceImpl commFireOnemapService;
    private final FireQueryService fireQueryService;
    /**
     * todo 业务代码在controller中，后续需要优化
     */
    private final HistoryFireController historyFireController;

    private final SmsAliServerConfig smsAliServerConfig;

    @Autowired
    private CommFireSmsLogsDao commFireSmsLogsDao;

    @Autowired
    private UserInfoService userInfoService;


    @SuppressWarnings("unchecked")
    public DataReturn<PubSmsPushUriVo> search(String interactiveCode) {
        String cacheValue = RedisUtils.get(StrUtil.format(PREFIX_KEY, interactiveCode));
        if (StrUtil.isEmpty(cacheValue)) {
            String fireId = RedisUtils.get(StrUtil.format(PREFIX_KEY_FID,interactiveCode));
            if (StrUtil.isEmpty(fireId)){
                throw new ForestBaseException("火情信息已经失效!");
            }
            PubSmsPushUriVo pubSmsPushUriVo = getPubSmsPushUriVo(null,Long.valueOf(fireId));
            cacheValue = JSONUtil.toJsonStr(pubSmsPushUriVo);
            RedisUtils.set(StrUtil.format(PREFIX_KEY, interactiveCode), cacheValue, KEY_EXPIRE_TIME);
        }
        return DataReturn.ok(JSONUtil.toBean(cacheValue, PubSmsPushUriVo.class));
    }

    /**
     * 短信发送方法
     *
     * @param fireId  火情id
     * @param mobiles 电话号码
     * @param status  短信模板状态码 1-真实火情模板，2-疑似火情模板，3-视频摄像头 拒绝 null
     * @return 发送结果，不保证一定发送成功，不保证为阿里短信是否成功发送，只保证触发
     */
    @SuppressWarnings("all")
    public boolean sendSms(Long fireId, List<String> mobiles, int status) throws InstantiationException, IllegalAccessException, ExecutionException, InterruptedException {
        final Class<Object> clazz = smsAliServerConfig.getParamClass(Convert.toStr(status));
        final String template = smsAliServerConfig.getTemplate(Convert.toStr(status));

        if (ObjectUtil.isNull(clazz) || StrUtil.isEmpty(template)) {
            log.error("短信调用失败,约束火情! status[{}]", status);
            return false;
        }
        final Object objParam = ClassUtil.createInstance(clazz, Boolean.FALSE);
        //查询火情信息
        final CommFireAlarm commFireAlarm = fireQueryService.queryById(fireId);
        final String interactiveCode = buildUrl(commFireAlarm);
        //临时处理 暂时不处理3
        if (status == 1) {
            final SmsRealFireDto dto = (SmsRealFireDto) objParam;
            dto.setCode(interactiveCode)
                    .setAddress(commFireAlarm.getDetailAddress());
            SmsUtils.sendContent(mobiles, template, dto);
        } else if (status == 2) {
            final SmsSuspectedFireDto dto = (SmsSuspectedFireDto) objParam;
            dto.setCode(interactiveCode)
                    .setContent(commFireAlarm.getDetailAddress());
            SmsUtils.sendContent(mobiles, template, dto);
        }
        //为跟踪短信来源，插入短信日志库
        insertFireSmsLogs(commFireAlarm);
        return true;
    }

    /**
     * 直接生成后端接口url
     *
     * @param commFireAlarm db火情实体
     * @return url返回
     */
    public String buildUrl(CommFireAlarm commFireAlarm) {
        final String key = buildInfo(commFireAlarm);
        //临时测试使用后端接口
        //return StrUtil.format("https://s.ahtelit.com/?{}", key);
        return key;
    }

    /**
     * 根据火情id 构造key 和数据
     *
     * @param commFireAlarm 火情实体对象
     * @return key值
     */
    public String buildInfo(CommFireAlarm commFireAlarm) {
        final String key = buildKey(commFireAlarm.getId());
        final PubSmsPushUriVo pubSmsPushUriVo = getPubSmsPushUriVo(commFireAlarm,null);
        //做非空判断，质量检测会有空指针情况
        if (ObjectUtil.isNotEmpty(pubSmsPushUriVo)) {
            RedisUtils.set(StrUtil.format(PREFIX_KEY, key), JSONUtil.toJsonStr(pubSmsPushUriVo), KEY_EXPIRE_TIME);
        }
        RedisUtils.set(StrUtil.format(PREFIX_KEY_FID, key), String.valueOf(commFireAlarm.getId()), KEY_EXPIRE_TIME_FID);
        return key;
    }

    /**
     * 获取火情信息
     *
     * @param commFireAlarm
     * @param fireId 火情id
     * @return 火情信息
     */
    private PubSmsPushUriVo getPubSmsPushUriVo(CommFireAlarm commFireAlarm,Long fireId) {
        if (ObjectUtil.isEmpty(commFireAlarm)) {
            commFireAlarm = fireQueryService.queryById(fireId);
        }
        PubSmsPushUriVo pubSmsPushUriVo = PubSmsPushUriVo.builder()
                .pubSmsPushUriFireInfoVo(buildFireInfo(commFireAlarm))
                .pubSmsPushUriForestryInfoVo(buildForestryInfo(commFireAlarm.getId()))
                .pubSmsPushUriWeatherInfoVo(buildWeatherInfo(commFireAlarm.getId()))
                .build();
        return pubSmsPushUriVo;
    }

    /**
     * 根据 fireId +当前时间毫秒构造 key，通过md5生成唯一签名， bcd 转二进制 压缩数字后存放 4位int
     *
     * @param fireId
     * @return 生成key
     */
    @SuppressWarnings("all")
    private String buildKey(Long fireId) {
        //fireId 和 毫秒组成随机数
        final String fireIdRamdom = StrUtil.format("{}{}", fireId, DateUtil.thisMillsecond());
        final String md5 = MD5.create().digestHex(fireIdRamdom, Charset.defaultCharset());
        final String[] str = shortUrl(md5);
        return Convert.toStr(str[2]);
    }

    public static String[] shortUrl(String hex) {
        // 要使用生成 URL 的字符
        final String[] chars = new String[]{"a", "b", "c", "d", "e", "f", "g", "h",
                "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
                "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5",
                "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H",
                "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
                "U", "V", "W", "X", "Y", "Z"
        };
        String[] resUrl = new String[4];
        for (int i = 0; i < 4; i++) {
            String sTempSubString = hex.substring(i * 8, i * 8 + 8);
            long lHexLong = 0x3FFFFFFF & Long.parseLong(sTempSubString, 16);
            String outChars = "";
            for (int j = 0; j < 6; j++) {
                long index = 0x0000003D & lHexLong;
                outChars += chars[(int) index];
                lHexLong = lHexLong >> 5;
            }
            // 把字符串存入对应索引的输出数组
            resUrl[i] = outChars;
        }
        return resUrl;
    }

    /**
     * 构造火情信息
     *
     * @param commFireAlarm 火情实体
     * @return 查询结果视图层 {@link PubSmsPushUriFireInfoVo}
     */
    private PubSmsPushUriFireInfoVo buildFireInfo(CommFireAlarm commFireAlarm) {
        //火情逻辑沿用现成业务逻辑--后续根据需要重写
        final PubSmsPushUriFireInfoVo resVo = PubSmsPushUriFireInfoVo.builder().build();
        if (ObjectUtil.isNotNull(commFireAlarm)) {
//            final Map<String, List<String>> mediaMap = ObjectUtil.isNull(commFireAlarm.getImageUrl()) ? null
//                    : MediaUrlUtils.handleMediaUrlToList(commFireAlarm.getImageUrl()).stream().collect(
//                            Collectors.groupingBy(url ->
//                                    StrUtil.split(url, StrUtil.SLASH)[4]
//                            ));
            Map<String, List<MultimediaDTO>> stringListMap = fireQueryService.queryMediaById(commFireAlarm.getId());
            List<MultimediaDTO> audioList = stringListMap.get("audioList");
            List<MultimediaDTO> imgList = stringListMap.get("imgList");
            List<MultimediaDTO> videoList = stringListMap.get("videoList");
            List<MultimediaDTO> docList = stringListMap.get("docList");
            resVo.setFireStatus(commFireAlarm.getStatus())
                    .setCallPoliceTime(DateUtil.format(commFireAlarm.getFindTime(), DatePattern.NORM_DATETIME_PATTERN))
                    .setRegionCodeCn(commFireAlarm.getDistrictName())
                    .setFireAddress(commFireAlarm.getDetailAddress())
                    .setLongitude(commFireAlarm.getLongitude())
                    .setLatitude(commFireAlarm.getLatitude())
                    .setCallPoliceOriginType(commFireAlarm.getResource())
                    .setCallPoliceOriginName(commFireAlarm.getFinderName())
                    .setFireDescription(commFireAlarm.getContent());
            if (CollectionUtil.isNotEmpty(audioList)) {
                resVo.setFireSoundUrl(audioList.stream().map(MultimediaDTO::getMediaUrl).collect(Collectors.toList()));
            }
            if (CollectionUtil.isNotEmpty(imgList)) {
                resVo.setFireImageUrl(imgList.stream().map(MultimediaDTO::getMediaUrl).collect(Collectors.toList()));
            }
            if (CollectionUtil.isNotEmpty(videoList)) {
                resVo.setFireVideoUrl(videoList.stream().map(MultimediaDTO::getMediaUrl).collect(Collectors.toList()));
            }
        }
        return resVo;
    }

    /**
     * 构造林业信息
     *
     * @param fireId 火情id
     * @return 查询结果视图层 {@link PubSmsPushUriForestryInfoVo}
     */
    private PubSmsPushUriForestryInfoVo buildForestryInfo(Long fireId) {
        final PubSmsPushUriForestryInfoVo resVo = PubSmsPushUriForestryInfoVo.builder().build();
        final CommFireOnemap entity = new CommFireOnemap();
        //db 有值则处理
        if (ObjectUtil.isNotNull(entity)) {
            resVo.setForestryType(entity.getSenLinLb())
                    //无法获取海拔
                    .setAltitude(null)
                    .setLandType(entity.getDiLei())
                    .setSlopeDegree(Convert.toStr(entity.getPoDu()))
                    .setSlopeDirection(entity.getPoXiang())
                    .setSlopePosition(entity.getPoWei())
                    .setYearsGroup(entity.getLingZu())
                    .setWellTreeSpecies(entity.getYouShiSz());
        }
        return resVo;
    }

    /**
     * 构造天气信息
     *
     * @param fireId 火情id
     * @return 查询结果视图层 {@link PubSmsPushUriWeatherInfoVo}
     */
    @SuppressWarnings("unchecked")
    private PubSmsPushUriWeatherInfoVo buildWeatherInfo(Long fireId) {
        final PubSmsPushUriWeatherInfoVo resVo = PubSmsPushUriWeatherInfoVo.builder().build();
        //悲观判定业务执行失败，为了保障火情部分短信可以正常发送
        try {
            final DataReturn<CommHistoryFire> dataReturn = historyFireController.queryById(fireId);
            final CommHistoryFire commHistoryFire = dataReturn.getData();
            if (ObjectUtil.isNotNull(commHistoryFire)) {
                resVo.setWeatherInfo(commHistoryFire.getWeatherCondition())
                        .setLowerHumidity(commHistoryFire.getMinimumHumidity())
                        .setHighTemperature(commHistoryFire.getMaximumTemperature())
                        .setLowTemperature(commHistoryFire.getMinimumTemperature())
                        .setWindDirection(commHistoryFire.getWindDirection())
                        .setWindLevel(commHistoryFire.getWindLevel())
                        .setWindSpeed(commHistoryFire.getWindSpeed())
                        .setRainfall(commHistoryFire.getRainfall());
            }
        } catch (Exception e) {
            log.error(StrUtil.format("火情Id为[{}],执行查询h5[构造天气信息查询失败],原因：[{}]", fireId, e.getMessage()));
        }
        return resVo;
    }

    /**
     * 短信日志记录
     * @param commFireAlarm
     */
    public void insertFireSmsLogs(CommFireAlarm commFireAlarm) {
        Long confirmId = commFireAlarm.getConfirmId();
        String confirmName = "";
        if (confirmId != null) {
            MicroSysUserAllInfoVo sysUserVo = userInfoService.getUserInfo(confirmId);
            if (sysUserVo != null) {
                confirmName = sysUserVo.getRealName();
            }
        }
        CommFireSmsLogs commFireSmsLogs = CommFireSmsLogs.builder()
                .findName(commFireAlarm.getFinderName())
                .confirmName(confirmName)
                .time(DateUtil.now())
                .address(commFireAlarm.getDetailAddress())
                .build();
        commFireSmsLogsDao.insert(commFireSmsLogs);
    }
}
